/**
 * ng-context-menu - v1.0.1 - An AngularJS directive to display a context menu
 * when a right-click event is triggered
 *
 * @author Ian Kennington Walter (http://ianvonwalter.com)
 */
angular
    .module('ng-context-menu', [])
    .factory('ContextMenuService', function() {
      return {
        element: null,
        menuElement: null
      };
    })
    .directive('contextMenu', [
      '$document',
      'ContextMenuService',
      function($document, ContextMenuService) {
        return {
          restrict: 'A',
          scope: {
            'callback': '&contextMenu',
            'disabled': '&contextMenuDisabled',
            'closeCallback': '&contextMenuClose'
          },
          link: function($scope, $element, $attrs) {
            var opened = false;
            $('.dropdown').on('click',function(){
                $('.dropdown').removeClass('open');
            });
            $('body').on('click','.dropdown',function(){
              $('.dropdown').removeClass('open');
            });
            function adjustPosition(){
              // window height change then adjust menuElement properties
              // only adjust the top height overflow-y
              var top,height,
                  menuElement = angular.element(
                      document.getElementById($attrs.target)
                  ),
                  doc = $document[0].documentElement,
                  docTop = (window.pageYOffset || doc.scrollTop) -
                      (doc.clientTop || 0),
                  docHeight = doc.clientHeight + docTop,
                  elementHeight = menuElement[0] && menuElement[0].scrollHeight || 0;

              if (elementHeight >= docHeight-$('.'+$attrs.navbar).height()){
                top = $('.'+$attrs.navbar).height();
                height = docHeight - $('.'+$attrs.navbar).height();
                if($('#'+$attrs.target+'>.dropdown-menu').length){
                  $('#'+$attrs.target+'>.dropdown-menu').css({
                    'height': height + 'px',
                    'overflow-y': 'auto'
                  });
                }
              }else{
                top = docHeight - elementHeight;
                if($('#'+$attrs.target+'>.dropdown-menu').length){
                  $('#'+$attrs.target+'>.dropdown-menu').css({
                    'height': 'auto',
                    'overflow-y': 'initial'
                  });
                }
              }
              menuElement.css('top', top + 'px');
            }
            $scope.$watch(function(){
              return $document[0].documentElement.clientHeight;
            },function(newValue){
              adjustPosition()
            }
            ,true);
            function open(event, menuElement) {
              menuElement.addClass('open');
              //console.log('======open context menu====');
              if($('#'+$attrs.target+'>.dropdown-menu').length){
                $('#'+$attrs.target+'>.dropdown-menu').css({
                  'height': 'auto',
                  'overflow': 'initial'
                });
              }
              var doc = $document[0].documentElement;
              var docLeft = (window.pageXOffset || doc.scrollLeft) -
                      (doc.clientLeft || 0),
                  docTop = (window.pageYOffset || doc.scrollTop) -
                      (doc.clientTop || 0),
                  elementWidth = menuElement[0].scrollWidth,
                  elementHeight = menuElement[0].scrollHeight;
              var docWidth = doc.clientWidth + docLeft,
                  docHeight = doc.clientHeight + docTop,
                  totalWidth = elementWidth + event.pageX,
                  totalHeight = elementHeight + event.pageY,
                  left = Math.max(event.pageX - docLeft, 0),
                  top = Math.max(event.pageY - docTop, 0),
                  height ='';

              if (totalWidth > docWidth) {
                left = left - (totalWidth - docWidth);
              }

              if (totalHeight > docHeight) {
                top = top - (totalHeight - docHeight);
              }

              // elementHeight>documentHeight  overflow auto addClass adjustPosition
              // elementHeight = documentHeight-navHeight
              // elementHeight.top = navHeight

              if (elementHeight >= docHeight-$('.'+$attrs.navbar).height()){
                top = $('.'+$attrs.navbar).height();
                height = docHeight - $('.'+$attrs.navbar).height();
                if($('#'+$attrs.target+'>.dropdown-menu').length){
                  $('#'+$attrs.target+'>.dropdown-menu').css({
                    'height': height + 'px',
                    'overflow-y': 'auto'
                  });
                }
              }


              menuElement.css('top', top + 'px');
              menuElement.css('left', left + 'px');
              opened = true;
            }

            ContextMenuService.close = function(menuElement){
              menuElement.removeClass('open');

              if (opened) {
                $scope.closeCallback();
              }

              opened = false;
            };

            function close(menuElement) {
              menuElement.removeClass('open');

              if (opened) {
                $scope.closeCallback();
              }

              opened = false;
            }

            $element.bind('contextmenu', function(event) {
              //if($(this).find('.tooltip')) $(this).find('.tooltip').css({display:'none'});
              if (!$scope.disabled()) {
                if (ContextMenuService.menuElement !== null) {
                  close(ContextMenuService.menuElement);
                }
                ContextMenuService.menuElement = angular.element(
                    document.getElementById($attrs.target)
                );
                ContextMenuService.element = event.target;
                //console.log('set', ContextMenuService.element);

                event.preventDefault();
                event.stopPropagation();
                if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest') {
                  $scope.$apply(function() {
                    $scope.callback({ $event: event });
                  });
                  $scope.$apply(function() {
                    // hanle jquery dropdown
                    $('.dropdown').removeClass('open');
                    open(event, ContextMenuService.menuElement);
                  });
                }

              }
            });

            function handleKeyUpEvent(event) {
              if (!$scope.disabled() && opened && event.keyCode === 27) {
                if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest'){
                  $scope.$apply(function() {
                    close(ContextMenuService.menuElement);
                  });
                }
              }
            }

            function handleClickEvent(event) {
              if (!$scope.disabled() &&
                  opened &&
                  (event.button !== 2 ||
                  event.target !== ContextMenuService.element)) {
                if ($scope.$root.$$phase != '$apply' && $scope.$root.$$phase != '$digest'){
                  $scope.$apply(function() {
                    close(ContextMenuService.menuElement);
                  });
                }

              }
            }

            $document.bind('keyup', handleKeyUpEvent);
            // Firefox treats a right-click as a click and a contextmenu event
            // while other browsers just treat it as a contextmenu event
            $document.bind('click', handleClickEvent);
            $document.bind('contextmenu', handleClickEvent);

            $scope.$on('$destroy', function() {
              //console.log('destroy');
              $document.unbind('keyup', handleKeyUpEvent);
              $document.unbind('click', handleClickEvent);
              $document.unbind('contextmenu', handleClickEvent);
            });
          }
        };
      }
    ]);
